import { Injectable } from '@angular/core';

declare const monaco: any;

export interface CodeDecoration {
  startLine: number;
  endLine: number;
  backgroundColor?: string;
  className?: string;
  hoverMessage?: string;
}

export interface FoldingRegion {
  startLine: number;
  endLine: number;
  collapsed?: boolean;
}

@Injectable({
  providedIn: 'root'
})
export class MonacoEditorAdvancedService {
  private editorLoaded = false;
  private decorationIds: string[] = [];
  private viewZoneIds: string[] = []; // 添加ViewZone ID追踪
  private foldingProviderDisposable: any = null; // 用于持有和释放折叠提供者

  constructor() { }

  /**
   * 加载 Monaco Editor
   */
  async loadMonacoEditor(): Promise<void> {
    if (this.editorLoaded) {
      return Promise.resolve();
    }

    return new Promise((resolve, reject) => {
      // 设置 Monaco Editor 的路径
      (window as any).MonacoEnvironment = {
        getWorkerUrl: function (moduleId: string, label: string) {
          if (label === 'json') {
            return '/assets/monaco/language/json/json.worker.js';
          }
          if (label === 'css' || label === 'scss' || label === 'less') {
            return '/assets/monaco/language/css/css.worker.js';
          }
          if (label === 'html' || label === 'handlebars' || label === 'razor') {
            return '/assets/monaco/language/html/html.worker.js';
          }
          if (label === 'typescript' || label === 'javascript') {
            return '/assets/monaco/language/typescript/ts.worker.js';
          }
          return '/assets/monaco/editor/editor.worker.js';
        }
      };

      // 动态加载 Monaco Editor
      const script = document.createElement('script');
      script.src = '/assets/monaco/loader.js';
      script.onload = () => {
        (window as any).require.config({ paths: { 'vs': '/assets/monaco' } });
        (window as any).require(['vs/editor/editor.main'], () => {
          this.editorLoaded = true;
          resolve();
        });
      };
      script.onerror = () => {
        reject(new Error('Failed to load Monaco Editor'));
      };
      document.head.appendChild(script);
    });
  }

  /**
   * 创建一个可交互的ViewZone，用于替代原生折叠，显示折叠信息和展开按钮。
   * @param editor Monaco Editor实例
   * @param afterLineNumber 在哪一行之后插入ViewZone
   * @param hiddenLineCount 这个ViewZone代表了多少隐藏行
   * @param onExpand 回调函数，当用户点击展开时调用
   * @returns 返回创建的ViewZone的ID
   */
  createFoldingViewZone(editor: any, afterLineNumber: number, hiddenLineCount: number, onExpand: () => void): string {
    const container = document.createElement('div');
    container.className = 'monaco-folding-view-zone';
    container.style.cssText = `
      display: flex;
      align-items: center;
      justify-content: center;
      background: #f7f7f7;
      border-top: 1px solid #eee;
      border-bottom: 1px solid #eee;
      color: #888;
      font-style: italic;
      cursor: pointer;
      height: 24px;
      line-height: 24px;
      font-family: Menlo, Monaco, 'Courier New', monospace;
      font-size: 12px;
      transition: all 0.2s ease;
    `;
    container.innerHTML = `<span>··· 展开 ${hiddenLineCount} 行 ···</span>`;
    
    container.addEventListener('click', (e) => {
      e.stopPropagation();
      onExpand();
    });

    container.addEventListener('mouseenter', () => {
      container.style.background = '#e9e9e9';
      container.style.color = '#333';
    });

    container.addEventListener('mouseleave', () => {
      container.style.background = '#f7f7f7';
      container.style.color = '#888';
    });

    return this.addViewZone(editor, afterLineNumber, container, 1.2);
  }

  /**
   * 创建编辑器实例
   */
  createEditor(container: HTMLElement, options: any): any {
    if (!this.editorLoaded) {
      throw new Error('Monaco Editor not loaded');
    }

    const defaultOptions = {
      theme: 'vs',
      language: 'typescript',
      readOnly: true,
      minimap: { enabled: false },
      scrollBeyondLastLine: false,
      automaticLayout: true,
      lineNumbers: 'on',
      glyphMargin: true,
      folding: true,
      lineDecorationsWidth: 10,
      lineNumbersMinChars: 4,
      renderLineHighlight: 'none',
      fontSize: 14,
      wordWrap: 'on',
      scrollbar: {
        vertical: 'visible',
        horizontal: 'visible',
        useShadows: false,
        verticalHasArrows: false,
        horizontalHasArrows: false
      },
      overviewRulerLanes: 0,
      hideCursorInOverviewRuler: true,
      overviewRulerBorder: false
    };

    const mergedOptions = { ...defaultOptions, ...options };
    return monaco.editor.create(container, mergedOptions);
  }

  /**
   * 【已废弃】使用原生折叠功能来代替 setHiddenAreas。
   * 此方法会计算可见区域之间的间隙，将它们作为折叠区域，然后命令编辑器全部折叠。
   * @param editor Monaco Editor 实例
   * @param totalLines 文件总行数
   * @param visibleRanges 需要保持可见的代码区域
   */
  applyFoldingRanges(editor: any, totalLines: number, visibleRanges: { startLine: number; endLine: number }[]): void {
    const model = editor.getModel();
    if (!model) return;

    // 清理之前的折叠提供者，避免重复注册
    if (this.foldingProviderDisposable) {
      this.foldingProviderDisposable.dispose();
    }

    // 1. 计算需要折叠的区域（可见区域之间的间隙）
    const rangesToFold: FoldingRegion[] = [];
    let lastVisibleEnd = 0;

    // 根据可见区域排序，确保逻辑正确
    const sortedVisibleRanges = [...visibleRanges].sort((a, b) => a.startLine - b.startLine);

    sortedVisibleRanges.forEach(range => {
      if (range.startLine > lastVisibleEnd + 1) {
        // 发现间隙，添加为折叠区域
        rangesToFold.push({ startLine: lastVisibleEnd + 1, endLine: range.startLine - 1 });
      }
      lastVisibleEnd = range.endLine;
    });

    // 检查文件末尾是否存在最后的隐藏区域
    if (totalLines > lastVisibleEnd) {
      rangesToFold.push({ startLine: lastVisibleEnd + 1, endLine: totalLines });
    }

    // 2. 注册新的折叠范围提供者
    this.foldingProviderDisposable = monaco.languages.registerFoldingRangeProvider(model.getLanguageId(), {
      provideFoldingRanges: () => {
        return rangesToFold.map(r => ({
          start: r.startLine,
          end: r.endLine,
          kind: monaco.languages.FoldingRangeKind.Region
        }));
      }
    });

    // 3. 使用setTimeout确保提供者注册后，再执行折叠命令
    setTimeout(() => {
      editor.getAction('editor.foldAll').run();
    }, 250); // 给予足够的时间让编辑器响应
  }

  /**
   * 【已废弃】展开所有由 `applyFoldingRanges` 创建的折叠区域
   * @param editor Monaco Editor 实例
   */
  unfoldAll(editor: any): void {
    if (editor) {
      editor.getAction('editor.unfoldAll').run();
    }
  }

  /**
   * 【已废弃】使用 setHiddenAreas API 来隐藏代码区域，这是 Monaco Editor 的原生高效方法
   * @param editor - Monaco Editor 实例
   * @param totalLines - 文件总行数
   * @param visibleRanges - 需要保持可见的代码区域范围
   */
  setHiddenAreas(editor: any, totalLines: number, visibleRanges: { startLine: number; endLine: number }[]): void {
    if (!editor) return;

    const model = editor.getModel();
    if (!model) return;

    // 创建一个表示所有行都可见的初始状态
    const visibleLines = new Set<number>();
    visibleRanges.forEach(range => {
      for (let i = range.startLine; i <= range.endLine; i++) {
        visibleLines.add(i);
      }
    });

    // 计算出需要隐藏的区域
    const hiddenAreas: any[] = [];
    let start = -1;
    for (let i = 1; i <= totalLines + 1; i++) {
      if (!visibleLines.has(i) && start === -1) {
        start = i;
      } else if (visibleLines.has(i) && start !== -1) {
        hiddenAreas.push(new monaco.Range(start, 1, i - 1, 1));
        start = -1;
      }
    }
    
    // 注册折叠提供者，以在隐藏区域的边界显示折叠/展开图标
    monaco.languages.registerFoldingRangeProvider(model.getLanguageId(), {
      provideFoldingRanges: (model: any, context: any, token: any) => {
        return hiddenAreas.map(range => ({
          start: range.startLineNumber,
          end: range.endLineNumber,
          kind: monaco.languages.FoldingRangeKind.Region
        }));
      }
    });
    
    // 应用隐藏区域
    editor.setHiddenAreas(hiddenAreas);
  }

  /**
   * 【已废弃】清除编辑器中所有通过 setHiddenAreas API 设置的隐藏区域
   * @param editor - Monaco Editor 实例
   */
  clearHiddenAreas(editor: any): void {
    if (editor) {
      editor.setHiddenAreas([]);
    }
  }

  /**
   * 设置编辑器内容和语言
   */
  setEditorContent(editor: any, content: string, language?: string): any {
    const model = monaco.editor.createModel(content, language || 'typescript');
    editor.setModel(model);
    return model;
  }

  /**
   * 添加装饰器（背景色、边框等）
   */
  addDecorations(editor: any, decorations: CodeDecoration[]): void {
    const monacoDecorations = decorations.map(decoration => ({
      range: new monaco.Range(
        decoration.startLine, 1,
        decoration.endLine, Number.MAX_SAFE_INTEGER
      ),
      options: {
        isWholeLine: true,
        className: decoration.className || 'custom-line-decoration',
        backgroundColor: decoration.backgroundColor,
        hoverMessage: decoration.hoverMessage ? { value: decoration.hoverMessage } : undefined,
        linesDecorationsClassName: 'line-decoration-glyph'
      }
    }));

    // 清除之前的装饰器
    this.decorationIds = editor.deltaDecorations(this.decorationIds, monacoDecorations);
  }

  /**
   * 设置折叠区域
   */
  setFoldingRanges(editor: any, ranges: FoldingRegion[]): void {
    const model = editor.getModel();
    if (!model) return;

    // 注册折叠提供者
    monaco.languages.registerFoldingRangeProvider(model.getLanguageId(), {
      provideFoldingRanges: () => {
        return ranges.map(range => ({
          start: range.startLine,
          end: range.endLine,
          kind: monaco.languages.FoldingRangeKind.Region
        }));
      }
    });

    // 自动折叠指定的区域
    ranges.forEach(range => {
      if (range.collapsed !== false) { // 默认折叠
        editor.getAction('editor.fold').run();
      }
    });
  }

  /**
   * 创建ViewZone（在编辑器中插入自定义内容）
   */
  addViewZone(editor: any, afterLineNumber: number, content: HTMLElement, heightInLines: number = 1): string {
    const viewZone = {
      afterLineNumber: afterLineNumber,
      heightInLines: heightInLines,
      domNode: content,
      suppressMouseDown: false
    };

    const zoneId = editor.changeViewZones((accessor: any) => {
      return accessor.addZone(viewZone);
    });
    this.viewZoneIds.push(zoneId); // 追踪ViewZone ID
    return zoneId;
  }

  /**
   * 创建简化的折叠指示ViewZone - 展开按钮在行号区域
   */
  createCollapseIndicator(
    editor: any, 
    afterLineNumber: number, 
    hiddenLineStart: number,
    hiddenLineEnd: number
  ): string {
    const container = document.createElement('div');
    const hiddenLineCount = hiddenLineEnd - hiddenLineStart + 1;
    
    container.className = 'monaco-collapse-indicator';
    container.style.cssText = `
      display: flex;
      align-items: center;
      padding: 4px 16px;
      background: linear-gradient(135deg, #f8f9fa, #ffffff);
      border: 1px solid #e9ecef;
      border-left: 3px solid #ddd;
      margin: 1px 0;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
      font-size: 12px;
      color: #999;
      font-style: italic;
    `;

    container.innerHTML = `
      <span style="color: #999;">⋯ ${hiddenLineCount} 行被折叠 ⋯</span>
    `;

    return this.addViewZone(editor, afterLineNumber, container, 0.8);
  }

  /**
   * 创建行号区域的展开按钮ViewZone - 垂直排列
   */
  createLineNumberExpandZone(
    editor: any, 
    afterLineNumber: number, 
    hiddenLineStart: number,
    hiddenLineEnd: number,
    onExpandUp: (start: number, end: number) => void,
    onExpandDown: (start: number, end: number) => void,
    onExpandAll: (start: number, end: number) => void
  ): string {
    const container = document.createElement('div');
    const hiddenLineCount = hiddenLineEnd - hiddenLineStart + 1;
    const canExpandUp = hiddenLineStart > 1;
    const canExpandDown = hiddenLineEnd < (editor.getModel()?.getLineCount() || hiddenLineEnd);
    
    container.className = 'monaco-line-expand-zone';
    container.style.cssText = `
      display: flex;
      align-items: stretch;
      background: transparent;
      margin: 2px 0;
      padding: 0;
      min-height: 100px;
    `;

    // 行号区域 - 垂直排列：行号->向下展开->全部展开->向上展开->行号
    const lineNumberArea = document.createElement('div');
    lineNumberArea.style.cssText = `
      width: 60px;
      display: flex;
      flex-direction: column;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
      font-size: 10px;
      background: #f8f9fa;
      border-right: 1px solid #e9ecef;
    `;

    // 创建行号项目数组 - 按照新的顺序
    const items = [];
    
    // 起始行号
    items.push(`
      <div class="line-number-item start-line" style="
        display: flex;
        align-items: center;
        justify-content: center;
        height: 20px;
        border-bottom: 1px solid rgba(0, 0, 0, 0.05);
        color: #666;
        font-weight: 500;
        background: rgba(255, 255, 255, 0.3);
      ">${hiddenLineStart}</div>
    `);
    
    // 向下展开图标
    if (canExpandDown) {
      items.push(`
        <div class="line-number-item expand-down-icon" style="
          display: flex;
          align-items: center;
          justify-content: center;
          height: 20px;
          border-bottom: 1px solid rgba(0, 0, 0, 0.05);
          cursor: pointer;
          font-weight: bold;
          color: #007acc;
          transition: all 0.2s ease;
        " title="向下展开5行">▼</div>
      `);
    }
    
    // 全部展开图标
    items.push(`
      <div class="line-number-item expand-all-icon" style="
        display: flex;
        align-items: center;
        justify-content: center;
        height: 20px;
        border-bottom: 1px solid rgba(0, 0, 0, 0.05);
        cursor: pointer;
        font-weight: bold;
        color: #28a745;
        font-size: 14px;
        transition: all 0.2s ease;
      " title="展开这 ${hiddenLineCount} 行代码">●</div>
    `);
    
    // 向上展开图标
    if (canExpandUp) {
      items.push(`
        <div class="line-number-item expand-up-icon" style="
          display: flex;
          align-items: center;
          justify-content: center;
          height: 20px;
          border-bottom: 1px solid rgba(0, 0, 0, 0.05);
          cursor: pointer;
          font-weight: bold;
          color: #007acc;
          transition: all 0.2s ease;
        " title="向上展开5行">▲</div>
      `);
    }
    
    // 结束行号
    items.push(`
      <div class="line-number-item end-line" style="
        display: flex;
        align-items: center;
        justify-content: center;
        height: 20px;
        color: #666;
        font-weight: 500;
        background: rgba(255, 255, 255, 0.3);
      ">${hiddenLineEnd}</div>
    `);
    
    lineNumberArea.innerHTML = items.join('');

    // 添加内容区域
    const contentArea = document.createElement('div');
    contentArea.style.cssText = `
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0 16px;
      color: #999;
      font-style: italic;
      font-size: 12px;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    `;
    
    const textSpan = document.createElement('span');
    textSpan.textContent = `⋯ ${hiddenLineCount} 行被折叠 ⋯`;
    contentArea.appendChild(textSpan);

    // 添加点击事件处理
    lineNumberArea.addEventListener('click', (e: MouseEvent) => {
      e.stopPropagation();
      const target = e.target as HTMLElement;
      
      if (target.classList.contains('expand-up-icon')) {
        const expandStart = Math.max(1, hiddenLineStart - 5);
        const expandEnd = hiddenLineStart - 1;
        if (expandEnd >= expandStart) {
          onExpandUp(expandStart, expandEnd);
        }
      } else if (target.classList.contains('expand-down-icon')) {
        const totalLines = editor.getModel()?.getLineCount() || hiddenLineEnd;
        const expandStart = hiddenLineEnd + 1;
        const expandEnd = Math.min(totalLines, hiddenLineEnd + 5);
        if (expandEnd >= expandStart) {
          onExpandDown(expandStart, expandEnd);
        }
      } else if (target.classList.contains('expand-all-icon')) {
        onExpandAll(hiddenLineStart, hiddenLineEnd);
      }
    });
    
    // 添加悬停效果到图标
    lineNumberArea.addEventListener('mouseover', (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      if (target.classList.contains('expand-up-icon') || target.classList.contains('expand-down-icon')) {
        target.style.background = 'rgba(0, 122, 204, 0.15)';
        target.style.color = '#005a9e';
        target.style.transform = 'scale(1.2)';
      } else if (target.classList.contains('expand-all-icon')) {
        target.style.background = 'rgba(40, 167, 69, 0.15)';
        target.style.color = '#1e7e34';
        target.style.transform = 'scale(1.3)';
      }
    });
    
    lineNumberArea.addEventListener('mouseout', (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      if (target.classList.contains('expand-up-icon') || target.classList.contains('expand-down-icon')) {
        target.style.background = 'transparent';
        target.style.color = '#007acc';
        target.style.transform = 'scale(1.0)';
      } else if (target.classList.contains('expand-all-icon')) {
        target.style.background = 'transparent';
        target.style.color = '#28a745';
        target.style.transform = 'scale(1.0)';
      }
    });

    container.appendChild(lineNumberArea);
    container.appendChild(contentArea);

    return this.addViewZone(editor, afterLineNumber, container, 5); // 调整高度适应5行内容
  }

  /**
   * 移除ViewZone
   */
  removeViewZone(editor: any, zoneId: string): void {
    editor.changeViewZones((accessor: any) => {
      accessor.removeZone(zoneId);
    });
    this.viewZoneIds = this.viewZoneIds.filter(id => id !== zoneId); // 从追踪列表中移除
  }

  /**
   * 清除所有ViewZones
   */
  clearAllViewZones(editor: any): void {
    if (this.viewZoneIds.length > 0) {
      editor.changeViewZones((accessor: any) => {
        this.viewZoneIds.forEach(zoneId => {
          accessor.removeZone(zoneId);
        });
      });
      this.viewZoneIds = []; // 清空追踪列表
    }
  }

  /**
   * 跳转到指定行
   */
  revealLine(editor: any, lineNumber: number): void {
    editor.revealLineInCenter(lineNumber);
    editor.setPosition({ lineNumber, column: 1 });
  }

  /**
   * 折叠指定区域
   */
  foldRange(editor: any, startLine: number, endLine: number): void {
    editor.getAction('editor.foldRecursively').run();
  }

  /**
   * 展开指定区域
   */
  unfoldRange(editor: any, startLine: number, endLine: number): void {
    editor.getAction('editor.unfoldRecursively').run();
  }

  /**
   * 获取编辑器的可见行范围
   */
  getVisibleRanges(editor: any): { startLineNumber: number; endLineNumber: number }[] {
    return editor.getVisibleRanges();
  }

  /**
   * 监听编辑器事件
   */
  onDidChangeModelContent(editor: any, callback: () => void): any {
    return editor.onDidChangeModelContent(callback);
  }

  /**
   * 监听滚动事件
   */
  onDidScrollChange(editor: any, callback: (e: any) => void): any {
    return editor.onDidScrollChange(callback);
  }

  /**
   * 更新编辑器选项
   */
  updateOptions(editor: any, options: any): void {
    editor.updateOptions(options);
  }

  /**
   * 销毁编辑器
   */
  destroyEditor(editor: any): void {
    if (editor) {
      editor.dispose();
    }
  }

  /**
   * 【已废弃】实现"隐藏行"效果的核心方法
   * 通过重新构建内容并使用ViewZone来实现
   * @deprecated - 请改用 setHiddenAreas 方法以获得更好的性能和原生体验
   */
  simulateHiddenLines(
    editor: any, 
    fullContent: string, 
    visibleRanges: { startLine: number; endLine: number; id?: string }[],
    onExpandRegion: (startLine: number, endLine: number) => void
  ): void {
    // 先清除所有现有的ViewZones
    this.clearAllViewZones(editor);

    const lines = fullContent.split('\n');
    const visibleLines: string[] = [];
    const lineMapping: number[] = []; // 映射显示行号到原始行号
    const viewZonesToCreate: Array<{
      afterLineNumber: number;
      hiddenStart: number;
      hiddenEnd: number;
    }> = [];
    let currentDisplayLine = 1;

    // 创建可见性映射
    const visibilityMap = new Set<number>();
    visibleRanges.forEach(range => {
      for (let i = range.startLine; i <= range.endLine; i++) {
        visibilityMap.add(i);
      }
    });

    // 构建显示内容
    let i = 0;
    while (i < lines.length) {
      const lineNumber = i + 1;
      
      if (visibilityMap.has(lineNumber)) {
        // 可见行
        visibleLines.push(lines[i]);
        lineMapping.push(lineNumber);
        currentDisplayLine++;
        i++;
      } else {
        // 找到连续的隐藏行
        const hiddenStart = lineNumber;
        while (i < lines.length && !visibilityMap.has(i + 1)) {
          i++;
        }
        const hiddenEnd = i;
        const hiddenCount = hiddenEnd - hiddenStart + 1;

        // 添加占位符行
        visibleLines.push(`// ··· ${hiddenCount} 行被折叠 ···`);
        lineMapping.push(-1); // 标记为占位符行
        
        // 记录需要创建的ViewZone信息
        viewZonesToCreate.push({
          afterLineNumber: currentDisplayLine,
          hiddenStart: hiddenStart,
          hiddenEnd: hiddenEnd
        });

        currentDisplayLine++;
      }
    }

    // 更新编辑器内容
    const model = editor.getModel();
    if (model) {
      model.setValue(visibleLines.join('\n'));
    }

    // 自定义行号显示
    this.updateOptions(editor, {
      lineNumbers: (lineNumber: number) => {
        const originalLine = lineMapping[lineNumber - 1];
        return originalLine === -1 ? '---' : originalLine.toString();
      }
    });

    // 等待编辑器完全渲染后创建ViewZones
    if (viewZonesToCreate.length > 0) {
      // 使用requestAnimationFrame确保DOM更新完成
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          viewZonesToCreate.forEach(zone => {
            try {
              const zoneId = this.createLineNumberExpandZone(
                editor,
                zone.afterLineNumber,
                zone.hiddenStart,
                zone.hiddenEnd,
                (start, end) => onExpandRegion(start, end), // 向上展开
                (start, end) => onExpandRegion(start, end), // 向下展开
                (start, end) => onExpandRegion(start, end)  // 展开全部
              );
              console.log(`Created ViewZone ${zoneId} after line ${zone.afterLineNumber} for range ${zone.hiddenStart}-${zone.hiddenEnd}`);
            } catch (error) {
              console.error('Failed to create ViewZone:', error);
            }
          });
        });
      });
    }
  }
} 